class SceneSetting {
  constructor(viewer) {
    if (!viewer) throw new Error("no viewer object!");
    this.viewer = viewer;

    this.lastStage;
    this.sceneFog;

    this.silhouette;
    this.skylineAnayStages;

    this.inter;
  }
  //下雨
  startRain() {
    this.clearWeather();
    let _rain = new Cesium.PostProcessStage({
      name: "czm_rain",
      fragmentShader: FS_Rain(),
    });
    this.viewer.scene.postProcessStages.add(_rain);
    this.lastStage = _rain;
  }
  //下雪
  startSnow() {
    this.clearWeather();
    let _snow = new Cesium.PostProcessStage({
      name: "czm_snow",
      fragmentShader: FS_Snow(),
    });
    this.viewer.scene.postProcessStages.add(_snow);
    this.lastStage = _snow;
  }
  //清空下雨下雪
  clearWeather() {
    this.lastStage &&
      this.viewer.scene.postProcessStages.remove(this.lastStage);
    this.lastStage = null;
  }
  //开启天际线
  openSkylineAnay() {
    this.clearWeather();
    if (this.skylineAnayStages) {
      this.silhouette.enabled = true;
      return;
    }
    this.skylineAnayStages = this.viewer.scene.postProcessStages;
    let edgeDetection =
      Cesium.PostProcessStageLibrary.createEdgeDetectionStage();
    let postProccessStage = new Cesium.PostProcessStage({
      //此后处理阶段的唯一名称，供组合中其他阶段参考，如果未提供名称，将自动生成GUID
      // name:name,
      //unform着色器对象 textureScale
      fragmentShader:
        "uniform sampler2D colorTexture;" +
        "uniform sampler2D depthTexture;" +
        "varying vec2 v_textureCoordinates;" +
        "void main(void)" +
        "{" +
        "float depth = czm_readDepth(depthTexture, v_textureCoordinates);" +
        "vec4 color = texture2D(colorTexture, v_textureCoordinates);" +
        "if(depth<1.0 - 0.000001){" +
        "gl_FragColor = color;" +
        "}" +
        "else{" +
        "gl_FragColor = vec4(1.0,0.0,0.0,1.0);" +
        "}" +
        "}",
    });

    //PostProcessStage:要使用的片段着色器。默认sampler2D制服是colorTexture和depthTexture。
    let postProccesStage_1 = new Cesium.PostProcessStage({
      // name:obj.name+'_1',
      fragmentShader:
        "uniform sampler2D colorTexture;" +
        "uniform sampler2D redTexture;" +
        "uniform sampler2D silhouetteTexture;" +
        "varying vec2 v_textureCoordinates;" +
        "void main(void)" +
        "{" +
        "vec4 redcolor=texture2D(redTexture, v_textureCoordinates);" +
        "vec4 silhouetteColor = texture2D(silhouetteTexture, v_textureCoordinates);" +
        "vec4 color = texture2D(colorTexture, v_textureCoordinates);" +
        "if(redcolor.r == 1.0){" +
        "gl_FragColor = mix(color, vec4(5.0,0.0,0.0,1.0), silhouetteColor.a);" +
        "}" +
        "else{" +
        "gl_FragColor = color;" +
        "}" +
        "}",
      //uniform着色器对象
      uniforms: {
        redTexture: postProccessStage.name,
        silhouetteTexture: edgeDetection.name,
      },
    });

    //如果inputPreviousStageTexture 是 true，则每个阶段输入是场景渲染到的输出纹理或之前执行阶段的输出纹理
    //如果inputPreviousStageTexture是false，则合成中每个阶段的输入纹理都是相同的
    this.silhouette = new Cesium.PostProcessStageComposite({
      //PostProcessStage要按顺序执行 的 s 或组合的数组。
      stages: [edgeDetection, postProccessStage, postProccesStage_1],
      //是否执行每个后处理阶段，其中一个阶段的输入是前一个阶段的输出。否则每个包含阶段的输入是组合之前执行的阶段的输出
      inputPreviousStageTexture: false,
      //后处理阶段制服的别名
      uniforms: edgeDetection.uniforms,
    });
    this.skylineAnayStages.add(this.silhouette);
  }
  //关闭天际线
  closeSkylineAnay() {
    if (this.silhouette) {
      this.silhouette.enabled = false;
    }
  }
  //设置场景时间
  setSceneTime(houer = 10, min = 0, year = 2023, month = 10, day = 1) {
    this.viewer.clock.currentTime = Cesium.JulianDate.fromDate(
      new Date(year, month, day, houer, min, 0)
    ).clone();
  }
  //开启日照分析
  startSunshine(option = {}) {
    this.viewer.scene.globe.enableLighting = true;
    this.viewer.shadows = true;
    this.viewer.terrainShadows = Cesium.ShadowMode.RECEIVE_ONLY;
    this.viewer.shadowMap.darkness = option.darkness || 0.5; //阴影透明度--越大越透明

    let time = 0;
    // this.inter = setInterval(() => {
    // 	let date = option.date + time;
    // 	if (null == option.date) { //时间传空的时候，就从当前时间开始
    // 		date = new Date().getTime() + time
    // 		// console.log(date,'shijan++++++++++++++');

    // 	}
    // 	let utc = Cesium.JulianDate.fromDate(new Date(date))
    // 	this.viewer.clockViewModel.currentTime = Cesium.JulianDate.addHours(utc, 0, new Cesium
    // 		.JulianDate())
    // 	time = time + 1000 * 60 * (option.setp || 1)
    // }, option.speed || 500)
    this.viewer.clock.multiplier = option.timeStep || 1000;
    this.viewer.clock.shouldAnimate = true;
  }

  //移除日照分析
  clearSunshine() {
    this.viewer.scene.globe.enableLighting = false;

    this.viewer.shadows = false;

    this.viewer.terrainShadows = Cesium.ShadowMode.DISABLED;
    this.viewer.clock.shouldAnimate = false;
    if (this.inter) {
      clearInterval(this.inter);
      // this.inter = null;
    }
  }
  //开启全球等值线
  contourLine(spacing = 100) {
    let globe = this.viewer.scene.globe;
    this.viewer.scene.globe.enableLighting = true;
    let contourUniforms = {};

    // 使用等高线材质
    let material = Cesium.Material.fromType("ElevationContour");
    contourUniforms = material.uniforms;

    // 线宽2.0px
    contourUniforms.width = 2.0;
    // 高度间隔为150米
    contourUniforms.spacing = spacing;

    contourUniforms.color = Cesium.Color.RED;

    // 设置材质
    globe.material = material;
  }
  //清空等值线
  clearContourLine() {
    let material = Cesium.Material.fromType("Color");
    material.uniforms.color = new Cesium.Color(1.0, 1.0, 0.0, 0);
    this.viewer.scene.globe.material = material;
  }
  /**
   * 设置雾气
   * distance 可见范围
   *
   */
  setSceneFog(distance = 200) {
    this.clearSceneFog();
    let fog = new Cesium.PostProcessStage({
      name: "sceneFog",
      fragmentShader: FS_Fog(),
      uniforms: {
        fogByDistance: new Cesium.Cartesian4(1.0, 0.0, distance, 1.0),
        fogColor: new Cesium.Color(1, 1, 1, 0.75), //避免看不了地球。设置一点点透明度
      },
    });

    this.viewer.scene.postProcessStages.add(fog);
    this.sceneFog = fog;
  }
  clearSceneFog() {
    this.sceneFog && this.viewer.scene.postProcessStages.remove(this.sceneFog);
    this.sceneFog = null;
  }
  resetScene() {
    this.clearContourLine();
    this.clearSceneFog();
    this.clearSunshine();
    this.clearWeather();
    this.closeSkylineAnay();
  }
}

function FS_Fog() {
  return ` 
    float getDistance(sampler2D depthTexture, vec2 texCoords) 
    { 
        //它用于将从深度纹理中读取到的深度值进行解压缩，以便在着色器中进行深度测试和深度值比较等操作。
        //深度纹理通常用于实现阴影效果、深度检测等功能。
        //在Cesium中，深度值通常被存储在一个16位的纹理单元中，这个值被压缩成0到1之间的浮点数，以便节省显存空间。
        float depth = czm_unpackDepth(texture2D(depthTexture, texCoords)); 
        //若深度值为0，则返回无穷远
        if (depth == 0.0) { 
            return czm_infinity; 
        } 
        //将窗口坐标系(即屏幕坐标系)下的像素坐标转换为相机坐标系下的坐标
        vec4 eyeCoordinate = czm_windowToEyeCoordinates(gl_FragCoord.xy, depth); 
        //返回物体离相机的距离
        return -eyeCoordinate.z / eyeCoordinate.w; 
    } 
    //根据距离，在中间进行插值
    float interpolateByDistance(vec4 nearFarScalar, float distance) 
    { 
        //根据常识，雾应该是距离远，越看不清，近距离内的物体可以看清
        //因此近距离alpha=0，远距离的alpha=1.0
        //雾特效的起始距离
        float startDistance = nearFarScalar.x;
        //雾特效的起始alpha值
        float startValue = nearFarScalar.y;
        //雾特效的结束距离 
        float endDistance = nearFarScalar.z;
        //雾特效的结束alpha值
        float endValue = nearFarScalar.w; 
        //根据每段距离占总长度的占比，插值alpha，距离越远，alpha值越大。插值范围0,1。
        float t = clamp((distance - startDistance) / (endDistance - startDistance), 0.0, 1.0); 
        return mix(startValue, endValue, t); 
    } 
    vec4 alphaBlend(vec4 sourceColor, vec4 destinationColor) 
    { 
        return sourceColor * vec4(sourceColor.aaa, 1.0) + destinationColor * (1.0 - sourceColor.a); 
    } 
    uniform sampler2D colorTexture; 
    uniform sampler2D depthTexture; 
    uniform vec4 fogByDistance; 
    uniform vec4 fogColor; 
    varying vec2 v_textureCoordinates; 
    void main(void) 
    { 
        //获取地物距相机的距离
        float distance = getDistance(depthTexture, v_textureCoordinates);
        //获取场景原本的纹理颜色 
        vec4 sceneColor = texture2D(colorTexture, v_textureCoordinates);
        //根据距离，对alpha进行插值
        float blendAmount = interpolateByDistance(fogByDistance, distance); 
        //将alpha变化值代入雾的原始颜色中，并将雾与场景原始纹理进行融合
        vec4 finalFogColor = vec4(fogColor.rgb, fogColor.a * blendAmount); 
        gl_FragColor = alphaBlend(finalFogColor, sceneColor); 
    }`;
}

//下雨着色器
function FS_Rain() {
  return "uniform sampler2D colorTexture;\n\
          varying vec2 v_textureCoordinates;\n\
        \n\
          float hash(float x){\n\
            return fract(sin(x*133.3)*13.13);\n\
        }\n\
        \n\
        void main(void){\n\
        \n\
          float time = czm_frameNumber / 60.0;\n\
        vec2 resolution = czm_viewport.zw;\n\
        \n\
        vec2 uv=(gl_FragCoord.xy*2.-resolution.xy)/min(resolution.x,resolution.y);\n\
        vec3 c=vec3(.6,.7,.8);\n\
        \n\
        float a=-.4;\n\
        float si=sin(a),co=cos(a);\n\
        uv*=mat2(co,-si,si,co);\n\
        uv*=length(uv+vec2(0,4.9))*.3+1.;\n\
        \n\
        float v=1.-sin(hash(floor(uv.x*100.))*100.);\n\
        float b=clamp(abs(sin(15.*time*v+uv.y*(10./(2.+v))))-.95,0.,1.)*4.;\n\
        c*=v*b; \n\
        \n\
        gl_FragColor = mix(texture2D(colorTexture, v_textureCoordinates), vec4(c,1), 0.5);  \n\
        }\n\
  ";
}
//下雪着色器
function FS_Snow() {
  return "uniform sampler2D colorTexture;\n\
          varying vec2 v_textureCoordinates;\n\
          \n\
          float snow(vec2 uv,float scale)\n\
          {\n\
              float time = czm_frameNumber / 60.0;\n\
              float w=smoothstep(1.,0.,-uv.y*(scale/10.));if(w<.1)return 0.;\n\
              uv+=time/scale;uv.y+=time*2./scale;uv.x+=sin(uv.y+time*.5)/scale;\n\
              uv*=scale;vec2 s=floor(uv),f=fract(uv),p;float k=3.,d;\n\
              p=.5+.35*sin(11.*fract(sin((s+p+scale)*mat2(7,3,6,5))*5.))-f;d=length(p);k=min(d,k);\n\
              k=smoothstep(0.,k,sin(f.x+f.y)*0.01);\n\
              return k*w;\n\
          }\n\
          \n\
          void main(void){\n\
              vec2 resolution = czm_viewport.zw;\n\
              vec2 uv=(gl_FragCoord.xy*2.-resolution.xy)/min(resolution.x,resolution.y);\n\
              vec3 finalColor=vec3(0);\n\
              float c = 0.0;\n\
              c+=snow(uv,30.)*.0;\n\
              c+=snow(uv,20.)*.0;\n\
              c+=snow(uv,15.)*.0;\n\
              c+=snow(uv,10.);\n\
              c+=snow(uv,8.);\n\
          c+=snow(uv,6.);\n\
              c+=snow(uv,5.);\n\
              finalColor=(vec3(c)); \n\
              gl_FragColor = mix(texture2D(colorTexture, v_textureCoordinates), vec4(finalColor,1), 0.5); \n\
          \n\
          }\n\
          ";
}

export default SceneSetting;
